//@author A0099619J
#include "Date.h"

const int Date::daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const std::string Date::months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
									"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const std::string Date::weekDays[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

Date Date::sevenDaysLater;

Date::Date() {
	*this = NULL_DATE;
}

Date::Date(int dd, int mm, int yy) {
	day = dd;
	month = mm;
	year = yy;
}

Date Date::getCurrentDate() {
	time_t t = time(0);
    struct tm now;
	localtime_s(&now, &t);

	Date date(now.tm_mday, now.tm_mon + 1, now.tm_year % 100);
	return date;
}

std::string Date::formatDate() {
	if (*this == NULL_DATE)
		return "NIL";

	if (*this == getCurrentDate()) {
		return "Today";
	}
	else if (*this == getCurrentDate() + 1) {
		return "Tomorrow";
	}
	else if (getCurrentDate() < *this && *this <= sevenDaysLater) {
		return weekDays[dayOfWeek()];
	}
	else {
		if (year > 10)
			return std::to_string(day) + " " + months[month-1] + " " + std::to_string(year);
		else
			return std::to_string(day) + " " + months[month-1] + " 0" + std::to_string(year);
	}
}

int Date::dayOfWeek() {
	time_t t = time(0);
    struct tm date;
	localtime_s(&date, &t);

	date.tm_year = year + 100;
	date.tm_mon = month - 1;
	date.tm_mday = day;

	mktime(&date);

	return date.tm_wday;
}

bool Date::isValidDate() {
	if (month < 1 || month > 12) {
		return false;
	}
	if (isLeapYear(year) && month == 2 && day == 29) {
		return true;
	}
	if (day < 1 || day > daysInMonth[month-1]) {
		return false;
	}
	return true;
}

bool Date::isLeapYear(int year) {
	if (year % 400 == 0) {
		return true;
	}
	else if (year % 100 == 0) {
		return false;
	}
	else if (year % 4 == 0) {
		return true;
	}
	else {
		return false;
	}
}

int Date::getYear()
{
	return year;
}

int Date::getMonth()
{
	return month;
}

int Date::getDay()
{
	return day;
}

bool Date::operator<(const Date& other) const
{
	if (year < other.year)
		return true;
	if (year == other.year && month < other.month)
		return true;
	if (year == other.year && month == other.month && day < other.day)
		return true;
	return false;
}

bool Date::operator<=(const Date& other) const
{
	if (year < other.year)
		return true;
	if (year == other.year && month < other.month)
		return true;
	if (year == other.year && month == other.month && day <= other.day)
		return true;
	return false;
}

bool Date::operator>(const Date& other) const
{
	if (year > other.year)
		return true;
	if (year == other.year && month > other.month)
		return true;
	if (year == other.year && month == other.month && day > other.day)
		return true;
	return false;
}

bool Date::operator>=(const Date& other) const
{
	if (year > other.year)
		return true;
	if (year == other.year && month > other.month)
		return true;
	if (year == other.year && month == other.month && day >= other.day)
		return true;
	return false;
}

bool Date::operator==(const Date& other) const
{
	return year == other.year && month == other.month && day == other.day;
}

bool Date::operator!=(const Date& other) const
{
	return !(*this == other);
}

Date Date::operator+(const int& daysLater) const
{
    struct tm date;
	date.tm_mday = day + daysLater;
	date.tm_mon = month - 1;
	date.tm_year = year + 100;
	
	mktime(&date);
	return Date(date.tm_mday, date.tm_mon + 1, date.tm_year - 100);
}

void Date::updateSevenDaysLater()
{
	sevenDaysLater = getCurrentDate() + 7;
}

std::ostream& operator<<(std::ostream& os, const Date& t)
{
	if (t.day < 10) {
		os << 0;
	}
	os << t.day * 10000 + t.month * 100 + t.year;
	return os;
}